# -*- coding: utf-8 -*-
import binascii
from os.path import *
from urlparse import urlsplit

import xml.dom.minidom as dom
from renyare.wsgi import RenyareMiddleware, nsp

_requires = ['renyare.config', 'renyare.page', 'renyare.applications']
_provides = ['renyare.stylesheets']

XSLT_NS = "http://www.w3.org/1999/XSL/Transform"
XSLT_NSP = 'xsl:'

class Styler(RenyareMiddleware):
	"""
	A WSGI middleware, that adds style and skin to output and allows to switch
	between them
	"""
	output = ""

	def call(self, environ, start_response):
		self.skin = self.skin or self.cf.get('renyare', 'skin')
		self.static = normpath(join(self.cf.get('paths', 'local'), 'static'))
		self.wstatic = self.cf.get('paths', 'web')+'/static'
		if(self.environ.get('renyare.page')):
			info = self.environ['renyare.page']['info']
			xml = self.environ['renyare.page']['document']
			skin = info.appendChild(xml.createElement(nsp+'skin'))
			skin.appendChild(xml.createTextNode(self.skin))
		self.transform = environ['renyare.transform']
		if self.transform:
			self.local_transform = True
		else:
			self.local_transform = False
		# Process underlying WSGI levels
		for data in self.app(self.environ, start_response):
			yield data
		self.sheet = self.make_sheet('html')
		self.stylesheets_local = []
		self.stylesheets_web = []
		self.add_sheets()
		self._embed()

	def add_sheets(self):
		for ss in self.cf.get('renyare', 'stylesheets').split(','):
			self._add_xsl(ss.strip(' '))
		# Add each application's own stylesheet
		if('renyare.applications' in self.environ):
			apps = self.environ['renyare.applications']
			for app in apps:
				path = app['full_name']
				if('.' in app['full_name']):
					if(self.local_transform):
						path = normpath(join(*app['full_name'].split('.')))
					else:
						path = '/'.join(app['full_name'].split('.'))
				self._add_xsl(path+'.xsl') # Add default stylesheet
				if(app.has_key('styles')):
					for ss in app['styles']['xsl']:
						self._add_xsl(ss) # Add stylesheets provided by application

	def _embed(self):
		"""
		Creates a node and embeds there the stylesheet, which includes all other stylesheets required
		"""
		ss_list = []
		if(self.local_transform):
			ss_list = self.stylesheets_local
		else:
			ss_list = self.stylesheets_web
		for ss in ss_list:
			incl = self.sxml.createElementNS(XSLT_NS, XSLT_NSP+'include')
			incl.setAttributeNS(None, 'href', ss)
			self.sxml.documentElement.appendChild(incl)
		xsl_string = self.sxml.toxml('UTF-8')
		crc = binascii.crc32(xsl_string)
		crc = binascii.hexlify(str(crc))
		if(self.local_transform):
			cache = self.cf.get('paths', 'internal')
		else:
			cache = self.static
		cache = normpath(join(cache, 'cache'))
		xsl_file = cache+'/'+str(crc)+'.xsl'
		if(not isfile(xsl_file)):
			f = file(xsl_file, 'wb')
			f.write(xsl_string)
		if(self.local_transform):
			self.transform.stylesheet = xsl_file
		# Append stylesheet link to main content
		if(not self.local_transform and self.environ.has_key('renyare.page')):
			xml = self.environ['renyare.page']['document']
			xsl_url = self.wstatic+'/cache/'+str(crc)+'.xsl'
			print xsl_url
			pi = xml.createProcessingInstruction(u'xml-stylesheet', u'type="application/xml" href="%s"' %xsl_url)
			xml.insertBefore(pi, xml.documentElement)

	def _add_xsl(self, sheet):
		"""
		Detect the stylesheet record type(file or URL) and location(depends of skin), if the type is file.
		Add full stylesheet reference into the generated stylesheet
		"""
		# Check if given location is url
		if(not '' in urlsplit(sheet)[0:3]):
			if(not sheet in self.stylesheets_local):
				self.stylesheets_local.append(sheet)
			if(not sheet in self.stylesheets_web):
				self.stylesheets_web.append(sheet)
		# Check if path is already absolute
		elif isabs(sheet):
			self.stylesheets_local.append(sheet)
		else:
			skin = normpath(join( self.static, 'skins', "%s", sheet))
			skinned_ss = skin % self.skin
			non_skinned_ss = skin % 'default'
			url = self.wstatic+'/skins/%s/'+sheet
			if(isfile(skinned_ss)): # There is a ss in skin directory
				stylesheet = skinned_ss
				stylesheet_url = url % self.skin
			elif(isfile(non_skinned_ss)): # There is no ss in skin directory, but there is in default directory
				stylesheet = non_skinned_ss
				stylesheet_url = url % 'default'
			else:
				print "Skipped files (not found): %s; %s" % (skinned_ss, non_skinned_ss)
				self.log.debug("Skipped files (not found): %s; %s" % (skinned_ss, non_skinned_ss))
				return False
			if(not stylesheet in self.stylesheets_local): # Add stylesheet path to local list
				self.stylesheets_local.append(stylesheet)
			if(not stylesheet_url in self.stylesheets_web): # Add stylesheet url to urls list
				self.stylesheets_web.append(stylesheet_url)

	def make_sheet(self, output='xml'):
		"""
		Generate a stylesheet skeleton
		"""
		impl = dom.getDOMImplementation()
		self.sxml = impl.createDocument(XSL_NS, XSL_NSP+'stylesheet', None)
		sheet = self.sxml.documentElement
		sheet.setAttribute('version', '1.0')
		# Generate output instructions
		out = self.sxml.createElementNS(XSL_NS, XSL_NSP+'output')
		if(output == 'xml'):
			out.setAttribute('method', 'xml')
			out.setAttribute('version', '1.0')
		elif(output == 'html'):
			out.setAttribute('method', 'html')
			out.setAttribute('version', '4.0')
			out.setAttribute('doctype-public', '-//W3C//DTD XHTML 1.0 Strict//EN')
			out.setAttribute('doctype-system', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd')
		out.setAttribute('omit-xml-declaration', 'yes')
		out.setAttribute('encoding', 'UTF-8')
		out.setAttribute('indent', 'no')
		sheet.appendChild(out)
		return sheet
